package com.ibeeking.found.msg.rest.service.mq;

import com.alibaba.fastjson.JSON;
import com.ibeeking.found.common.entity.msg.EMailSimpleMsgSendParam;
import com.ibeeking.found.common.entity.msg.MsgTemplateParam;
import com.ibeeking.found.common.enums.msg.MsgReceiverTypeEnum;
import com.ibeeking.gmc.global.api.common.dto.TenantDTO;
import com.ibeeking.gmc.global.api.feign.GlobalTenantFeignClient;
import com.ibeeking.found.msg.api.common.dto.MemberInfoDTO;
import com.ibeeking.found.msg.api.common.dto.ShopDTO;
import com.ibeeking.found.msg.api.feign.MsgMemberBClient;
import com.ibeeking.found.msg.api.feign.MsgSystemBClient;
import com.ibeeking.found.msg.rest.service.*;
import com.ibeeking.found.msg.service.common.param.MsgNoticeParam;
import com.ibeeking.found.msg.service.common.param.MsgWxSendParam;
import com.ibeeking.found.msg.service.common.param.SysMsgSendParam;
import com.ibeeking.found.msg.service.common.vo.MsgBindConfigViewVO;
import com.ibeeking.found.msg.service.common.vo.WxMaMsgTemplateVO;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseCodeEnum;
import com.ibeeking.nematos.utils.result.ResponseResult;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @ClassName NoticeMsgSender
 * @Description 消息实现类
 * @Author ibeeking
 * @Date 2020-12-10 9:21
 **/
@Service
public class NoticeMsgSender {

    @Resource
    private GlobalTenantFeignClient globalTenantFeignClient;

    @Resource
    private IMsgBindConfigService msgBaseInfoConfigServiceImpl;

    @Resource
    private MsgMemberBClient memberBFeignClient;

    @Resource
    private MsgSystemBClient systemBFeignClient;

    @Resource
    private ISendWxMaMsgService sendWxMaMsgServiceImpl;

    @Resource
    private ISendWxMpMsgService sendWxMpMsgServiceImpl;

    @Resource
    private ISendWxCpMsgService sendWxCpMsgServiceImpl;

    @Resource
    private ISendEmailService sendEmailServiceImpl;

    @Resource
    private ISendSysMsgService sendSysMsgServiceImpl;

    @Resource
    private ISendSmsService sendSmsServiceImpl;

    /**
     * 发送微信模板消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxMaSubscribeMessage(String tenantId, MsgWxSendParam param) {
        MsgBindConfigViewVO msgBaseInfoConfig = msgBaseInfoConfigServiceImpl.viewByCode(param.getTemplateCode());
        List<String> receiver = param.getReceiver();
        MemberInfoDTO memberInfoDto = getMemberInfoDto(Long.valueOf(receiver.get(0)));
        String maOpenId = memberInfoDto.getMaOpenId();
        // 发送小程序订阅消息
        WxMaMsgTemplateVO maMsgTemplate = msgBaseInfoConfig.getMaMsgTemplate();
        Map<String, String> paramMap = param.getParamMap();
        // oVOzU5GpGLoDpAA8cEQv22BrrQkY
        Boolean status = sendWxMaMsgServiceImpl.sendWxMaSubscribeMessage(maMsgTemplate, paramMap, maOpenId);
        return new AsyncResult<>(status);
    }

    /**
     * 发送公众号消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxMaTemplateMessage(String tenantId, String smsTemplateCode, MsgTemplateParam param) {
        try {
            // 发送短信消息
            Integer tenantID = Integer.valueOf(tenantId);
            Integer receiverType = param.getReceiverType();
            List<String> receivers = new ArrayList<>();
            if(receiverType == MsgReceiverTypeEnum.BUYER.getCode()){
                List<String>  memberIds = param.getReceivers();
                if(Collections3.isNotEmpty(memberIds)) {
                    List<Long> memeberIdList = memberIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    List<MemberInfoDTO> memberInfoDTOList = getMemberInfoList(memeberIdList);
                    if(Collections3.isNotEmpty(memberInfoDTOList)){
                        List<String> openIdsList = new ArrayList<>();
                        memberInfoDTOList.stream().forEach(d->{
                            String maOpenId = d.getMaOpenId();
                            if(StringUtils.isNotEmpty(maOpenId)){
                                openIdsList.add(maOpenId);
                            }
                        });
                        if(Collections3.isNotEmpty(openIdsList)){
                            receivers = openIdsList.stream().distinct().collect(Collectors.toList());
                        }
                    }
                }
            }

            if(Collections3.isNotEmpty(receivers)) {
                Boolean status = sendWxMaMsgServiceImpl.sendWxMaTemplateMessage(tenantID, smsTemplateCode, receivers, param.getParamMap());
                return new AsyncResult<>(status);
            }
            return new AsyncResult<>(false);
        } catch (WxErrorException e) {
            LogUtils.error("发送公众号消息失败", e);
            throw new BusinessException("发送公众号消息通知失败");
        }
    }

    /**
     * 发送公众号消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxMpTemplateMessage(String tenantId, String smsTemplateCode, MsgTemplateParam param) {
        try {
            // 发送短信消息
            Integer tenantID = Integer.valueOf(tenantId);
            Integer receiverType = param.getReceiverType();
            List<String> receivers = new ArrayList<>();
            if(receiverType == MsgReceiverTypeEnum.BUYER.getCode()){
                List<String>  memberIds = param.getReceivers();
                if(Collections3.isNotEmpty(memberIds)) {
                    List<Long> memeberIdList = memberIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    List<MemberInfoDTO> memberInfoDTOList = getMemberInfoList(memeberIdList);
                    if(Collections3.isNotEmpty(memberInfoDTOList)){
                        List<String> openIdsList = new ArrayList<>();
                        memberInfoDTOList.stream().forEach(d->{
                            String maOpenId = d.getMaOpenId();
                            if(StringUtils.isNotEmpty(maOpenId)){
                                openIdsList.add(maOpenId);
                            }
                        });
                        if(Collections3.isNotEmpty(openIdsList)){
                            receivers = openIdsList.stream().distinct().collect(Collectors.toList());
                        }
                    }
                }
            }
            if(Collections3.isNotEmpty(receivers)) {
                Boolean status = sendWxMpMsgServiceImpl.sendWxMpTemplateMessage(tenantID, smsTemplateCode, receivers, param.getParamMap());
                return new AsyncResult<>(status);
            }
            return new AsyncResult<>(false);
        } catch (WxErrorException e) {
            LogUtils.error("发送公众号消息失败", e);
            throw new BusinessException("发送公众号消息通知失败");
        }
    }
    /**
     * 发送公众号消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxMpSimpleMessage(MsgNoticeParam param) {
        Boolean status = sendWxMpMsgServiceImpl.sendWxMpSimpleMessage(param);
        return new AsyncResult<>(status);
    }
    /**
     * 发送公众号消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxMpMassMessage(MsgNoticeParam param) {
        Boolean status = sendWxMpMsgServiceImpl.sendWxMpMassMessage(param);
        return new AsyncResult<>(status);
    }

    /**
     * 发送公众号消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendWxCpTemplateMessage(String tenantId, String smsTemplateCode, MsgTemplateParam param) {
        try {
            // 发送短信消息
            Integer tenantID = Integer.valueOf(tenantId);
            Integer receiverType = param.getReceiverType();
            List<String> receivers = new ArrayList<>();
            if(receiverType == MsgReceiverTypeEnum.PLATFORM.getCode()) {
                List<String> tenantIds = param.getReceivers();
                Integer tenementID = Integer.valueOf(tenantId);
                if (Collections3.isNotEmpty(tenantIds)) {
                    tenementID = Integer.valueOf(tenantIds.get(0));
                }
                ResponseResult<TenantDTO> memberResult = globalTenantFeignClient.queryTenantById(tenementID);
                if (!ResponseCodeEnum.SUCCESS.getCode().equals(memberResult.getCode())) {
                    throw new BusinessException("根据memberId查询会员信息失败 memberId:" + tenementID + "code:" + memberResult.getCode());
                }
                TenantDTO tenantDTO = memberResult.getData();
                String mobile = tenantDTO.getMobile();
                if (StringUtils.isNotEmpty(mobile)) {
                    receivers.add(mobile);
                }
            }
            if(Collections3.isNotEmpty(receivers)) {
                Boolean status = sendWxCpMsgServiceImpl.sendWxCpTemplateMessage(tenantID, smsTemplateCode, receivers, param.getParamMap());
                return new AsyncResult<>(status);
            }
            return new AsyncResult<>(false);
        } catch (WxErrorException ex) {
            LogUtils.error("发送企业微信消息失败", ex);
            throw new BusinessException("发送企业微信消息通知失败");
        }
    }

        /**
     * 发送短信消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendSmsSimpleMessage(MsgNoticeParam param) {
        Boolean status = sendSmsServiceImpl.sendSmsSimpleMessage(param);
        return new AsyncResult<>(status);
    }
    /**
     * 发送短信消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendSmsTemplateMessage(String tenantId, String smsTemplateCode, MsgTemplateParam param) {
        // 发送短信消息
        Integer tenantID = Integer.valueOf(tenantId);
        Integer receiverType = param.getReceiverType();
        List<String> receivers = new ArrayList<>();
        if(receiverType == MsgReceiverTypeEnum.BUYER.getCode()){
            List<String>  memberIds = param.getReceivers();
            if(Collections3.isNotEmpty(memberIds)) {
                List<Long> memeberIdList = memberIds.stream().map(Long::valueOf).collect(Collectors.toList());
                List<MemberInfoDTO> memberInfoDTOList = getMemberInfoList(memeberIdList);
                if(Collections3.isNotEmpty(memberInfoDTOList)){
                    List<String> mobileList = new ArrayList<>();
                    memberInfoDTOList.stream().forEach(d->{
                        String mobile = d.getPhone();
                        if(StringUtils.isNotEmpty(mobile)){
                            mobileList.add(mobile);
                        }
                    });
                    if(Collections3.isNotEmpty(mobileList)){
                        receivers = mobileList.stream().distinct().collect(Collectors.toList());
                    }
                }
            }
        }else if(receiverType == MsgReceiverTypeEnum.PLATFORM.getCode()){
            List<String>  tenantIds = param.getReceivers();
            Integer tenementID = Integer.valueOf(tenantId);
            if(Collections3.isNotEmpty(tenantIds)) {
                tenementID = Integer.valueOf(tenantIds.get(0));
            }
            ResponseResult<TenantDTO> memberResult = globalTenantFeignClient.queryTenantById(tenementID);
            if (!ResponseCodeEnum.SUCCESS.getCode().equals(memberResult.getCode())) {
                throw new BusinessException("根据memberId查询会员信息失败 memberId:" + tenementID + "code:" + memberResult.getCode());
            }
            TenantDTO tenantDTO =  memberResult.getData();
            String mobile = tenantDTO.getMobile();
            if(StringUtils.isNotEmpty(mobile)){
                receivers.add(mobile);
            }
        }else if(receiverType == MsgReceiverTypeEnum.SELLER.getCode()){
            List<String>  shopIds = param.getReceivers();
            if(Collections3.isNotEmpty(shopIds)) {
                List<Long> shopsIdList = shopIds.stream().map(Long::valueOf).collect(Collectors.toList());
                List<ShopDTO> shopDTOList = getShopInfoList(shopsIdList);
                if(Collections3.isNotEmpty(shopDTOList)){
                    List<String> mobileList = new ArrayList<>();
                    shopDTOList.stream().forEach(d->{
                        String mobile = d.getTel();
                        if(StringUtils.isNotEmpty(mobile)){
                            mobileList.add(mobile);
                        }
                    });
                    if(Collections3.isNotEmpty(mobileList)){
                        receivers = mobileList.stream().distinct().collect(Collectors.toList());
                    }
                }
            }
        }

        if(Collections3.isNotEmpty(receivers)) {
            Boolean status = sendSmsServiceImpl.sendSmsTemplateMessage(tenantID, smsTemplateCode, receivers, param.getParamMap());
            return new AsyncResult<>(status);
        }
        return new AsyncResult<>(false);
    }

    /**
     * 发送简单邮件消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendEmailSimpleMessage(String tenantId, EMailSimpleMsgSendParam param) {
        // 发送邮件消息
        try {
            Boolean status = sendEmailServiceImpl.sendSimpleEmail(tenantId, param.getToUser(), param.getSubject(), param.getContent());
            return new AsyncResult<>(status);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.error("发送简单邮件消息通知失败", e);
            throw new BusinessException("发送简单邮件消息通知失败");
        }
    }

    /**
     * 发送模板邮件消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendEmailTemplateMessage(String tenantId, String emailTemplateCode, MsgTemplateParam param) {
        // 发送邮件消息
        try {
            Integer receiverType = param.getReceiverType();
            List<String> receivers = new ArrayList<>();
            if(receiverType == MsgReceiverTypeEnum.BUYER.getCode()) {
                List<String>  memberIds = param.getReceivers();
                if(Collections3.isNotEmpty(memberIds)) {
                    List<Long> memeberIdList = memberIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    List<MemberInfoDTO> memberInfoDTOList = getMemberInfoList(memeberIdList);
                    if(Collections3.isNotEmpty(memberInfoDTOList)){
                        List<String> emailList = new ArrayList<>();
                        memberInfoDTOList.stream().forEach(d->{
                            String email = d.getEmail();
                            if(StringUtils.isNotEmpty(email)){
                                emailList.add(email);
                            }
                        });
                        if(Collections3.isNotEmpty(emailList)){
                            receivers = emailList.stream().distinct().collect(Collectors.toList());
                        }
                    }
                }
            }else if(receiverType == MsgReceiverTypeEnum.PLATFORM.getCode()){
                List<String>  tenantIds = param.getReceivers();
                Integer tenantID = Integer.valueOf(tenantId);
                if(Collections3.isNotEmpty(tenantIds)) {
                    tenantID = Integer.valueOf(tenantIds.get(0));
                }
                ResponseResult<TenantDTO> memberResult = globalTenantFeignClient.queryTenantById(tenantID);
                if (!ResponseCodeEnum.SUCCESS.getCode().equals(memberResult.getCode())) {
                    throw new BusinessException("根据memberId查询会员信息失败 memberId:" + tenantID + "code:" + memberResult.getCode());
                }
                TenantDTO tenantDTO =  memberResult.getData();
                String email = tenantDTO.getEmail();
                if(StringUtils.isNotEmpty(email)){
                    receivers.add(email);
                }
            }else if(receiverType == MsgReceiverTypeEnum.SELLER.getCode()){
                List<String>  shopIds = param.getReceivers();
                if(Collections3.isNotEmpty(shopIds)) {
                    List<Long> shopsIdList = shopIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    List<ShopDTO> shopDTOList = getShopInfoList(shopsIdList);
                    if(Collections3.isNotEmpty(shopDTOList)){
                        List<String> emailList = new ArrayList<>();
                        shopDTOList.stream().forEach(d->{
                            String email = d.getEmail();
                            if(StringUtils.isNotEmpty(email)){
                                emailList.add(email);
                            }
                        });
                        if(Collections3.isNotEmpty(emailList)){
                            receivers = emailList.stream().distinct().collect(Collectors.toList());
                        }
                    }
                }
            }
            LogUtils.info(">>>>>>>receivers:{}", JsonUtils.toJsonStr(receivers));
            if(Collections3.isNotEmpty(receivers)) {
                Boolean status = sendEmailServiceImpl.sendTemplateEmail(tenantId, emailTemplateCode, receivers, param.getParamMap());
                return new AsyncResult<>(status);
            }
            return new AsyncResult<>(false);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.error("发送模板邮件消息通知失败", e);
            throw new BusinessException("发送模板邮件消息通知失败");
        }
    }

    /**
     * 发送系统消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendSysSimpleMessage(String tenantId, SysMsgSendParam param) {
        // 发送邮件消息
        try {
            Long tenantID = Long.valueOf(tenantId);
            Integer receiverType = param.getReceiverType();
            List<Long> receivers = param.getReceivers().stream().map(Long::valueOf).collect(Collectors.toList());
            Boolean status = sendSysMsgServiceImpl.sendSysSimpleMsg(tenantID, receiverType,receivers, param.getSubject(), param.getContent());
            return new AsyncResult<>(status);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.error("发送系统消息通知失败", e);
            throw new BusinessException("发送系统消息通知失败");
        }
    }

    /**
     * 发送系统模板消息通知
     *
     * @param param
     * @return
     */
    @Async
    public Future<Boolean> sendSysTemplateMesssage(String tenantId, String sysMsgTemplateCode, MsgTemplateParam param) {
        // 发送邮件消息
        try {
            Long tenantID = Long.valueOf(tenantId);
            Integer receiverType = param.getReceiverType();
            List<Long> receivers = new ArrayList<>();
            if(receiverType == MsgReceiverTypeEnum.BUYER.getCode()) {
                List<String>  memberIds = param.getReceivers();
                if(Collections3.isNotEmpty(memberIds)) {
                    List<Long> memeberIdList = memberIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    receivers = memeberIdList.stream().distinct().collect(Collectors.toList());
                }
            }else if(receiverType == MsgReceiverTypeEnum.PLATFORM.getCode()){
                List<String>  tenantIds = param.getReceivers();
                Long tenementId = tenantID;
                if(Collections3.isNotEmpty(tenantIds)) {
                    tenementId = Long.valueOf(tenantIds.get(0));
                }
                receivers.add(tenementId);
            }else if(receiverType == MsgReceiverTypeEnum.SELLER.getCode()){
                List<String>  shopIds = param.getReceivers();
                if(Collections3.isNotEmpty(shopIds)) {
                    List<Long> shopsIdList = shopIds.stream().map(Long::valueOf).collect(Collectors.toList());
                    receivers = shopsIdList.stream().distinct().collect(Collectors.toList());
                }
            }
            if(Collections3.isNotEmpty(receivers)) {
                Boolean status = sendSysMsgServiceImpl.sendSysTemplateMsg(tenantID, sysMsgTemplateCode, receiverType, receivers, param.getParamMap());
                return new AsyncResult<>(status);
            }
            return new AsyncResult<>(false);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.error("发送系统模板消息通知失败", e);
            throw new BusinessException("发送系统模板消息通知失败");
        }
    }

    /**
     * 根据会员Id查询会员信息对象
     *
     * @param memberId
     * @return
     */
    private MemberInfoDTO getMemberInfoDto(Long memberId) {
        ResponseResult<MemberInfoDTO> memberResult = memberBFeignClient.infoOne(memberId);
        LogUtils.info("根据memberId查询会员信息返回 memberResult:" + JSON.toJSONString(memberResult));
        if (!ResponseCodeEnum.SUCCESS.getCode().equals(memberResult.getCode())) {
            throw new BusinessException("根据memberId查询会员信息失败 memberId:" + memberId + "code:" + memberResult.getCode());
        }
        return memberResult.getData();
    }

    /**
     * 根据会员Id查询会员信息对象
     *
     * @param memberIds
     * @return
     */
    private List<MemberInfoDTO> getMemberInfoList(List<Long> memberIds) {
        Set<Long> ids = new HashSet<>(memberIds);
        ResponseResult<List<MemberInfoDTO>> memberResultList = memberBFeignClient.memberInfo(ids);
        LogUtils.info("根据memberId查询会员信息返回 memberResult:" + JSON.toJSONString(memberResultList));
        if (!ResponseCodeEnum.SUCCESS.getCode().equals(memberResultList.getCode())) {
            throw new BusinessException("根据memberId查询会员信息失败 memberId:" + JSON.toJSONString(memberIds) + ":" + memberResultList.getCode());
        }
        return memberResultList.getData();
    }

    /**
     * 根据商户Id查询商户信息对象
     *
     * @param shopIds
     * @return
     */
    private List<ShopDTO> getShopInfoList(List<Long> shopIds) {
        ResponseResult<List<ShopDTO>> shopResultList = systemBFeignClient.queryListByShopIds(shopIds);
        LogUtils.info("根据shopIds查询商户信息返回 memberResult:" + JSON.toJSONString(shopResultList));
        if (!ResponseCodeEnum.SUCCESS.getCode().equals(shopResultList.getCode())) {
            throw new BusinessException("根据shopIds查询商户信息失败 memberId:" + JSON.toJSONString(shopIds) + ":" + shopResultList.getCode());
        }
        return shopResultList.getData();
    }
}
